package cn.jianml.validation.handler;

import cn.jianml.validation.entity.WebResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.List;
import java.util.Set;

/**
 * 全局异常处理
 * @author wujian
 * @time 2020/1/4
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public WebResult handleException(Exception e) {
        log.info("系统内部异常:{}", e.getMessage());
        return new WebResult().msg("系统内部异常:");
    }

    /**
     * 统一处理请求参数缺失异常
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e){
        log.info("参数缺失异常：{}", e.getMessage());
        String missingParameterName = e.getParameterName();
        return new WebResult().msg("缺少参数{" + missingParameterName + "}");
    }

    /**
     * 统一处理请求参数校验(普通传参)
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult handleConstraintViolationException(ConstraintViolationException e){
        log.info("普通参数异常：{}", e.getMessage());

        StringBuilder msgBuilder = new StringBuilder();
        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            Path path = violation.getPropertyPath();
            String[] pathArr = path.toString().split("\\.");
            msgBuilder.append(pathArr[1]).append(violation.getMessage()).append(",");
        }
        msgBuilder = new StringBuilder(msgBuilder.substring(0, msgBuilder.length() - 1));
        return new WebResult().msg(msgBuilder.toString());
    }

    /**
     * 统一处理请求参数校验(被@RequestBody注解的实体对象传参)
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
        log.info("实体对象参数异常：{}", e.getMessage());

        StringBuilder msgBuilder = new StringBuilder();

        List<ObjectError>  objectErrors = e.getBindingResult().getAllErrors();
        for (ObjectError objectError : objectErrors) {
            msgBuilder.append(objectError.getDefaultMessage()).append(",");
        }
        msgBuilder = new StringBuilder(msgBuilder.substring(0, msgBuilder.length() - 1));

        return new WebResult().msg(msgBuilder.toString());
    }

    /**
     * 统一处理请求参数校验(普通实体对象传参)
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult handleBindException(BindException e){
        log.info("实体对象参数异常：{}", e.getMessage());

        StringBuilder msgBuilder = new StringBuilder();
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        for (FieldError error : fieldErrors) {
            msgBuilder.append(error.getField()).append(error.getDefaultMessage()).append(",");
        }
        msgBuilder = new StringBuilder(msgBuilder.substring(0, msgBuilder.length() - 1));
        return new WebResult().msg(msgBuilder.toString());
    }

}
